﻿Imports System
Imports System.Net.NetworkInformation
Imports System.Deployment.Application
Imports System.Reflection

Namespace Common
    Module ClickOnceCommon

#Region "CheckForNewVersion Methods"

        ''' <summary>
        ''' Checks for new version.
        ''' </summary>
        ''' <returns>
        ''' true if a new version was found, false otherwise
        ''' </returns>
        Public Function CheckForNewVersion() As Boolean
            Dim dtTimeOfLastUpdateCheck As DateTime = DateTime.Now.AddYears(-1)
            Return CheckForNewVersion(dtTimeOfLastUpdateCheck)
        End Function

        ''' <summary>
        ''' Checks for new version.
        ''' </summary>
        ''' <param name="dtTimeOfLastUpdateCheck">time of last update check</param>
        ''' <returns>true if a new version was found, false otherwise</returns>
        Public Function CheckForNewVersion(ByRef dtTimeOfLastUpdateCheck As DateTime) As Boolean
            Return CheckForNewVersion(dtTimeOfLastUpdateCheck, 0)
            ' Zero means use the default
        End Function

        ''' <summary>
        ''' Checks for new version.
        ''' </summary>
        ''' <param name="dtTimeOfLastUpdateCheck">time of last update check</param>
        ''' <param name="bShowMessageIfUnavailable">if set to <c>true</c> [show message if unavailable].</param>
        ''' <returns>
        ''' true if a new version was found, false otherwise
        ''' </returns>
        Public Function CheckForNewVersion(ByRef dtTimeOfLastUpdateCheck As DateTime, bShowMessageIfUnavailable As Boolean) As Boolean
            Return CheckForNewVersion(dtTimeOfLastUpdateCheck, 0, bShowMessageIfUnavailable)
            ' Zero means use the default
        End Function

        ''' <summary>
        ''' Checks for new version.
        ''' </summary>
        ''' <param name="dtTimeOfLastUpdateCheck">time of last update check</param>
        ''' <param name="iHoursBetweenUpdateChecks">hours between update checks</param>
        ''' <returns>
        ''' true if a new version was found, false otherwise
        ''' </returns>
        Public Function CheckForNewVersion(ByRef dtTimeOfLastUpdateCheck As DateTime, iHoursBetweenUpdateChecks As Integer) As Boolean
            Return CheckForNewVersion(dtTimeOfLastUpdateCheck, iHoursBetweenUpdateChecks, False)
        End Function

        ''' <summary>
        ''' Checks for new version.
        ''' </summary>
        ''' <param name="dtTimeOfLastUpdateCheck">time of last update check</param>
        ''' <param name="iHoursBetweenUpdateChecks">hours between update checks</param>
        ''' <param name="bShowMessageIfUpgradeUnavailable">if set to <c>true</c> [show message if upgrade unavailable].</param>
        ''' <returns>
        ''' true if a new version was found, false otherwise
        ''' </returns>
        Public Function CheckForNewVersion(ByRef dtTimeOfLastUpdateCheck As DateTime, iHoursBetweenUpdateChecks As Integer, bShowMessageIfUpgradeUnavailable As Boolean) As Boolean
            Return CheckForNewVersionI(dtTimeOfLastUpdateCheck, iHoursBetweenUpdateChecks, bShowMessageIfUpgradeUnavailable)
        End Function

        Private Function CheckForNewVersionI(ByRef dtTimeOfLastUpdateCheck As DateTime, iHoursBetweenUpdateChecks As Integer, bShowMessageIfUpgradeUnavailable As Boolean) _
            As Boolean
            'Verify the allowable hours between checks
            Const MAX_HOURS_BETWEEN As Integer = 24 * 7

            '7 days max
            If iHoursBetweenUpdateChecks <= 0 Then
                iHoursBetweenUpdateChecks = 24
            ElseIf iHoursBetweenUpdateChecks > MAX_HOURS_BETWEEN Then
                iHoursBetweenUpdateChecks = MAX_HOURS_BETWEEN
            End If

            'If the network is not available, bypass the check
            If Not NetworkInterface.GetIsNetworkAvailable() Then
                If bShowMessageIfUpgradeUnavailable Then
                    MessageBox.Show("No network is available at this time.")
                End If
                Return False
            End If

            If (DateTime.Now - dtTimeOfLastUpdateCheck) > New TimeSpan(iHoursBetweenUpdateChecks, 0, 0) Then
                Dim oUpdateCheckInfo As UpdateCheckInfo

                If Not ApplicationDeployment.IsNetworkDeployed Then
                    ' Do the check manually
                    ' Return CheckForNewVersionLegacy(dtTimeOfLastUpdateCheck, bShowMessageIfUpgradeUnavailable)
                    Return False
                End If

                Dim oApplicationDeployment As ApplicationDeployment = ApplicationDeployment.CurrentDeployment

                Try
                    oUpdateCheckInfo = oApplicationDeployment.CheckForDetailedUpdate()
                Catch oDeploymentDownloadException As DeploymentDownloadException
                    MessageBox.Show(
                        String.Format(
                            "The new version of the application cannot be downloaded at this time. " & Environment.NewLine &
                            "Please check your network connection, or try again later. Error: {0}", oDeploymentDownloadException.Message))
                    Return False
                Catch oInvalidDeploymentException As InvalidDeploymentException
                    MessageBox.Show(
                        String.Format(
                            "Cannot check for a new version of the application. The ClickOnce deployment is corrupt. Please redeploy the application and try again. Error: {0}",
                            oInvalidDeploymentException.Message))
                    Return False
                Catch oInvalidOperationException As InvalidOperationException
                    MessageBox.Show(String.Format("This application cannot be updated. It is likely not a ClickOnce application. Error: {0}", oInvalidOperationException.Message))
                    Return False
                End Try

                If oUpdateCheckInfo.UpdateAvailable Then
                    If Not oUpdateCheckInfo.IsUpdateRequired Then
                        Dim oDialogResult As DialogResult = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available",
                                                                            MessageBoxButtons.OKCancel)
                        If DialogResult.OK <> oDialogResult Then
                            Return False
                        End If
                    Else
                        ' Display a message that the app MUST reboot. Display the minimum required version.
                        MessageBox.Show(
                            String.Format(
                                "This application has detected a mandatory update from your current version to version {0}. The application will now install the update and restart.",
                                oUpdateCheckInfo.MinimumRequiredVersion), "Update Available", MessageBoxButtons.OK, MessageBoxIcon.Information)
                    End If

                    ' Try to do the update
                    Try
                        oApplicationDeployment.Update()
                        MessageBox.Show("The application has been upgraded, and will now restart.")
                        Application.Restart()
                        Return True
                    Catch oDeploymentDownloadException As DeploymentDownloadException
                        MessageBox.Show(
                            String.Format(
                                "Cannot install the latest version of the application. " & Environment.NewLine &
                                "Please check your network connection, or try again later. Error: {0}", oDeploymentDownloadException))
                        Return False
                    End Try
                End If
            End If

            If bShowMessageIfUpgradeUnavailable Then
                MessageBox.Show("No application updates are available at this time.")
            End If
            dtTimeOfLastUpdateCheck = DateTime.Now
            Return False
        End Function

#End Region

        ''' <summary>
        ''' Gets the version number of the click once application.
        ''' </summary>
        ''' <returns>if the application running from the ClickOnce installation this will return the current deployment version, .
        ''' otherwise this returns the file version.
        ''' </returns>
        Public Function GetVersionNumber(Optional ByVal bUseFileVersion As Boolean = False) As String
            If ApplicationDeployment.IsNetworkDeployed Then
                Return ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString()
            End If

            If (bUseFileVersion) Then
                Return FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).FileVersion
            Else
                Return Assembly.GetExecutingAssembly().GetName().Version.ToString()
            End If
        End Function

        ''' <summary>
        ''' Adds the click once version number to the end of the form title "e.g. original name - version".
        ''' </summary>
        ''' <param name="oWindowsForm">windows form</param>
        Public Sub AddVersionNumberToFormTitle(oWindowsForm As Form, Optional ByVal bUseFileVersion As Boolean = False)
            Try
                oWindowsForm.Text = String.Format("{0} - {1}", oWindowsForm.Text, GetVersionNumber(bUseFileVersion))
            Catch
            End Try
        End Sub
    End Module
End Namespace